iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0
Software Development

Rails Active Model系列 第 11

D-11 Active Model 自定義可共用的 validator - 2

  • 分享至 

  • xImage
  •  

今天接續上篇來介紹一下,假如在 validates 方法代入 options 作為 validator,有什麼應該注意的地方~

假設我建立一個對輸入 csv 的表頭進行驗證的 validator HeadersValidator,想要驗證輸入的 csv 一定要有指定的欄位,我希望的使用方式像這樣:

  validates :csv, headers: ["name", "age"]

那我要怎麼知道,我傳入的 ["name", "age"] 會被放在 validator 的哪裡?我在 validator 內要怎麼引用?
我們可以透過 initialize 來觀察看看,validates 這個 method 會怎麼 parse 我們輸入的設定。

# 先透過把傳入參數印出來,看看他到底會怎麼傳入。
class HeadersValidator < ActiveModel::EachValidator
  def initialize(*args)
    p args
  end
end

class MyClass
  include ActiveModel::Model
  validates :csv, headers: ["name", "age"]
end

印出如下

[{:attributes=>[:csv], :in=>["name", "age"], :class=>MyClass}]

我們可以發現,initialize 傳入的 argument 只會有一個 Hash,且我們帶入的 array 被傳到了 :in 這個 key。

之所以會這樣,是因為在使用 validates 這方法時,rails 會根據傳入的 validator 底下的 value 去做對應的 pre-parse,把輸入的值整理成一包 options。

根據 source code 的 parse 規則如下:

如果傳入 hash: 照使用者輸入的原樣
ex: validates :csv, headers: { in: ["name", "age"] }
如果只給 true: 給一包空的 {}
ex: validates :csv, headers: true
如果傳入 array 或是 range: 把 value 放在 :in 變成 {in: ["name", "age"]}
ex: validates :csv, headers: ["name", "age"]
其他的像是 string or regex 等等: 把 value 放在 :with 變成 {with: "string"}
ex: validates :csv, headers: "string"

而這包 options 會在排除掉 :attributes 以及 :class 兩個 key 之後,存放在 validator 的 @options 裡面。
ActiveModel::Validator 有使用 attr_reader :options 建立 method,所以代表我們可以讀取實體變數,也可以使用 options 這個 method 去拉出當初輸入的這包 options。

所以我們的 validator 可以這樣寫:

class HeadersValidator < ActiveModel::EachValidator
  def validate_each(record, attr_name, csv)
    # 設定驗證的 csv 欄位要全部都有才算合格
    return if (options[:in] & csv.headers) == options[:in]
    record.errors.add(attr_name, :invalid_headers)
  end

  def check_validity!
    # 這邊驗證當其他人使用這個 validator 時需要輸入 array
    unless options[:in].is_a?(Array)
      raise "should be array."
    end
  end
end

這樣,您的自訂 validator 就做好啦~

不知道讀者們會不會好奇一個問題,那就是很多的 validation 都是使用像是 validates_presence_of 這樣的 helper method 在進行設定的,那我要如何自訂一個 helper method 才能像上面的自訂驗證器一樣可以全專案共享呢?

下回見分曉~


上一篇
D-10 Active Model 自定義可共用的 validator - 1
下一篇
D-12 Active Model 自定義可共用的 validator - 3
系列文
Rails Active Model28
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言